﻿using System;
using System.Collections.Concurrent;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Timers;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using HuaWeiCamera.Class;
using HuaWeiCamera.Enums;
using HuaWeiCamera.Enums.Media;
using HuaWeiCamera.Enums.Video;
using HuaWeiCamera.Model;
using HuaWeiCamera.Struct;
using HuaWeiCamera.Struct.Face;
using OpenCvSharp;
using Window = System.Windows.Window;

namespace HuaWeiCamera
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {

        private uint _ulIdentifyId;
        private uint _ulRealHandleId;
        private static bool _isSave;
        private static bool _isExit;
        private static ConcurrentQueue<CaptureInfo> _concurrentQueue = new ConcurrentQueue<CaptureInfo>();
        private static readonly FileStream VideoFileStream = new FileStream(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "test.mp4"), FileMode.Append);

        private static HuaWeiSdkHelper.PfRealDataCallBack _fedRealPlayCallbackWithYUV;
        private static HuaWeiSdkHelper.PfRealDataCallBack _fedRealPlayCallbackFaceCapture;
        private const uint ByteLength = 1920 * 1080 * 4;
        private static readonly VideoYuvModelView VideoYuvModelView = new VideoYuvModelView();
        private IntPtr _videoPlayHandle = IntPtr.Zero;
        private Timer _timer;

        [DllImport("kernel32.dll")]
        private static extern void CopyMemory(IntPtr destination, IntPtr source, uint length);

        public MainWindow()
        {
            InitializeComponent();
            VideoYuvModelView.VideoWriteableBitmap = new WriteableBitmap(1920, 1800, 96.0, 96.0, PixelFormats.Bgr32, null);
        }

        private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
        {
            CanvaVideo.DataContext = VideoYuvModelView;
            _videoPlayHandle = ImagePlay.Handle;
            _timer = new Timer(300)
            {
                Enabled = false
            };
            _timer.Elapsed += Timer_Elapsed;
        }

        #region 处理人脸数据
        private void Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (_concurrentQueue.Count == 0)
            {
                Console.WriteLine(@"暂无人脸图片");
                return;
            }

            if (!_concurrentQueue.TryDequeue(out CaptureInfo face))
            {
                Console.WriteLine(@"读取队列错误");
                return;
            }

            if (face._dataFacePic != null && face._dataFacePic.Length > 0)
            {
                Console.WriteLine(@"人脸存储中");
                Task.Run(async () =>
                {
                    var saveFaceFile = Path.Combine($"{AppDomain.CurrentDomain.BaseDirectory}", "jpg", $"face_{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.jpg");

                    await YuvHelper.Byte2Jpg(face._dataFacePic, saveFaceFile).ConfigureAwait(false);
                });
            }

            if (face._dataFacePanorama != null && face._dataFacePanorama.Length > 0)
            {
                Console.WriteLine(@"全景图片存储中");
                Task.Run(async () =>
                {
                    var savePanoramaFile = Path.Combine($"{AppDomain.CurrentDomain.BaseDirectory}", "jpg", $"Panorama_{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.jpg");

                    await YuvHelper.Byte2Jpg(face._dataFacePanorama, savePanoramaFile).ConfigureAwait(false);
                });
            }


        }
        #endregion

        #region 视频预览（自动和手动处理视频流）

        private void ButtonView_OnClick(object sender, RoutedEventArgs e)
        {
            if (0 == _ulIdentifyId)
            {
                HuaWeiSdkHelper.InitAndLogin("192.168.2.250", 6060, "ApiAdmin", "HuaWei123", out _ulIdentifyId, out string errMsg);

                if (0 == _ulIdentifyId)
                {
                    MessageBox.Show(errMsg);
                    return;
                }
            }
            var prpInfos = new PU_REAL_PLAY_INFO_S[1];
            var clientInfo = new PU_REAL_PLAY_INFO_S
            {
                ulChannelId = 101,
                hPlayWnd = _videoPlayHandle,
                enProtocolType = PU_PROTOCOL_TYPE.PU_PROTOCOL_TYPE_TCP,
                enStreamType = PU_STREAM_TYPE.PU_VIDEO_MAIN_STREAM,
                enVideoType = PU_VIDEO_TYPE.PU_VIDEO_TYPE_VIDEO,
                enMediaCryptoType = PU_MEDIA_CRYPTO_TYPE.PU_MEDIA_CRYPTO_NONE,
                enMediaCallbackType = PU_MEDIA_CALLBACK_TYPE.PU_MEDIA_CALLBACK_TYPE_RTP,
                szReserved = new byte[32],
                bKeepLive = true
            };

            IntPtr pUsrData = (IntPtr)_ulIdentifyId;
            if (RadioButtonManual.IsChecked == true)
            {
                //手动处理视频预览
                FormsHostVideo.Visibility = Visibility.Collapsed;
                CanvaVideo.Visibility = Visibility.Visible;
                clientInfo.hPlayWnd = IntPtr.Zero;
                clientInfo.enMediaCallbackType = PU_MEDIA_CALLBACK_TYPE.PU_MEDIA_CALLBACK_TYPE_YUV;
                prpInfos[0] = clientInfo;
                _fedRealPlayCallbackWithYUV = FedRealPlayCallbackWithYUV; //手动处理的时候使用
                _ulRealHandleId = HuaWeiSdkHelper.IVS_PU_RealPlay(_ulIdentifyId, prpInfos, _fedRealPlayCallbackWithYUV, ref pUsrData);
                if (0 == _ulRealHandleId)
                {
                    MessageBox.Show(HuaWeiSdkHelper.GetLastErrorInfo());
                }

                ButtonSaveOne.IsEnabled = true;
            }
            else
            {
                CanvaVideo.Visibility = Visibility.Collapsed;
                FormsHostVideo.Visibility = Visibility.Visible;
                prpInfos[0] = clientInfo;
                //传入句柄，自动预览
                _ulRealHandleId = HuaWeiSdkHelper.IVS_PU_RealPlay(_ulIdentifyId, prpInfos, null, ref pUsrData);
                if (0 == _ulRealHandleId)
                {
                    MessageBox.Show(HuaWeiSdkHelper.GetLastErrorInfo());
                }
            }
        }

        #region 手动解析YUV数据并展示在界面上
        private static void FedRealPlayCallbackWithYUV(IntPtr szBuffer, int lSize, IntPtr pUsrData)
        {
            if (_isExit) return;
            try
            {

                Span<byte> nativeSpan;
                unsafe
                {
                    nativeSpan = new Span<byte>(szBuffer.ToPointer(), lSize);
                }

                if (nativeSpan.Length > 0)
                {
                    #region 处理视频流YUV图像

                    Mat yuvImg = new Mat(1080 * 3/2, 1920, MatType.CV_8UC1);
                    Mat rgbImg = new Mat(1080, 1920, MatType.CV_8UC1);

                    Marshal.Copy(nativeSpan.ToArray(), 0, yuvImg.Data, nativeSpan.Length);
                    Cv2.CvtColor(yuvImg, rgbImg, ColorConversionCodes.YUV2RGBA_I420);
                    Application.Current.Dispatcher?.InvokeAsync(() =>
                    {
                        VideoYuvModelView.VideoWriteableBitmap.Lock();
                        unsafe
                        {
                            //Buffer.MemoryCopy(rgbImg.DataPointer, _bitmap.BackBuffer.ToPointer(), _bytenLength, _bytenLength);
                            CopyMemory(VideoYuvModelView.VideoWriteableBitmap.BackBuffer, new IntPtr(rgbImg.DataPointer), ByteLength);
                        }
                        VideoYuvModelView.VideoWriteableBitmap.AddDirtyRect(new Int32Rect(0, 0, 1920, 1080));
                        VideoYuvModelView.VideoWriteableBitmap.Unlock();
                    });
                    //YuvHelper.SavePic(_bitmap, Path.Combine($"{AppDomain.CurrentDomain.BaseDirectory}", "jpg", $"{Guid.NewGuid()}.jpg"));

                    if (_isSave)
                    {
                        Cv2.ImWrite(
                            Path.Combine($"{AppDomain.CurrentDomain.BaseDirectory}", "jpg",
                                $"{Guid.NewGuid()}.jpg"), rgbImg);
                        _isSave = false;
                    }

                    #endregion
                }
            }
            catch (Exception e)
            {
                App.NewNLog.Error($"写入视频文件出错：{e}");
            }
        }
        #endregion

        #endregion

        #region 人脸捕获
        private void ButtonFace_OnClick(object sender, RoutedEventArgs e)
        {
            if (0 == _ulIdentifyId)
            {
                HuaWeiSdkHelper.InitAndLogin("192.168.2.250", 6060, "ApiAdmin", "HuaWei123", out _ulIdentifyId,
                    out string errMsg);

                if (0 == _ulIdentifyId)
                {
                    MessageBox.Show(errMsg);
                    return;
                }
            }

            var prpInfos = new PU_REAL_PLAY_INFO_S[1];
            var clientInfo = new PU_REAL_PLAY_INFO_S
            {
                ulChannelId = 101,
                hPlayWnd = IntPtr.Zero,
                enProtocolType = PU_PROTOCOL_TYPE.PU_PROTOCOL_TYPE_TCP,
                enStreamType = PU_STREAM_TYPE.PU_VIDEO_MAIN_STREAM,
                enVideoType = PU_VIDEO_TYPE.PU_VIDEO_TYPE_META,
                enMediaCryptoType = PU_MEDIA_CRYPTO_TYPE.PU_MEDIA_CRYPTO_NONE,
                enMediaCallbackType = PU_MEDIA_CALLBACK_TYPE.PU_MEDIA_CALLBACK_TYPE_META_FRAME,
                bKeepLive = true,
                szLocalIp = null,
                szReserved = new byte[32]
            };
            clientInfo.szReserved[22] = 1;//szReserved[22]表示智能分析数据打包格式 0:XML,1:元数据
            prpInfos[0] = clientInfo;
            var loginUserId = _ulIdentifyId;
            IntPtr pUsrData = (IntPtr)loginUserId;
            _fedRealPlayCallbackFaceCapture = FaceCaptureReaplayCallbackWithMetaFrame;
            var ulRealHandleCapture = HuaWeiSdkHelper.IVS_PU_RealPlay(_ulIdentifyId, prpInfos, _fedRealPlayCallbackFaceCapture, ref pUsrData);
            if (0 == ulRealHandleCapture)
            {
                MessageBox.Show(HuaWeiSdkHelper.GetLastErrorInfo());
                return;
            }

            _timer.Enabled = true;
        }

        #region 人脸捕获数据回调

        private static void FaceCaptureReaplayCallbackWithMetaFrame(IntPtr szBuffer, int lSize, IntPtr pUsrData)
        {
            var ptrstMetaTargetData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PU_META_DATA)));
            try
            {
                var bRet = HuaWeiSdkHelper.IVS_User_GetMetaData(szBuffer, lSize, LAYER_TWO_TYPE.TARGET, ref ptrstMetaTargetData);
                if (false == bRet)
                {
                    return;
                }

                if ((IntPtr)0 == ptrstMetaTargetData)
                {
                    return;
                }

                //将数据从非托管内存块封送到新分配的指定类型的托管对象
                var pstMetaData = (PU_META_DATA)Marshal.PtrToStructure(ptrstMetaTargetData, typeof(PU_META_DATA));
                //数据处理
                if (0 == pstMetaData.usValidNumber)
                {
                    return;
                }

                PU_UserData pstMetaUserData = new PU_UserData();
                int nSizeofPuUserDataInC = Marshal.SizeOf(pstMetaUserData);
                byte[] dataFacePic = null;
                byte[] dataFacePanorama = null;
                var faceFeature = new META_FACE_ATTRIBUTES();
                bool hasFaceFeature = false;
                int target = 0;
                for (int uIndex = 0; uIndex < pstMetaData.usValidNumber; ++uIndex)
                {
                    IntPtr ptr2 = new IntPtr(pstMetaData.pstMetaUserData.ToInt32() + nSizeofPuUserDataInC * uIndex);
                    pstMetaUserData = (PU_UserData)Marshal.PtrToStructure(ptr2, typeof(PU_UserData));
                    switch (pstMetaUserData.eType)
                    {
                        case LAYER_THREE_TYPE.TARGET_TYPE:
                            target = pstMetaUserData.Union1.IntValue;
                            break;
                        case LAYER_THREE_TYPE.FACE_PIC://人脸抠图
                            dataFacePic = new byte[pstMetaUserData.Union1.stBinay.ulBinaryLenth];
                            //使用地址data来获取需要的内存块中的数据
                            Marshal.Copy(pstMetaUserData.Union1.stBinay.pBinaryData, dataFacePic, 0, (int)pstMetaUserData.Union1.stBinay.ulBinaryLenth);
                            break;
                        case LAYER_THREE_TYPE.FACE_PANORAMA://人脸全景
                            dataFacePanorama = new byte[pstMetaUserData.Union1.stBinay.ulBinaryLenth];
                            //使用地址data来获取需要的内存块中的数据
                            Marshal.Copy(pstMetaUserData.Union1.stBinay.pBinaryData, dataFacePanorama, 0, (int)pstMetaUserData.Union1.stBinay.ulBinaryLenth);
                            break;
                        case LAYER_THREE_TYPE.FACE_FEATURE://人脸属性
                            hasFaceFeature = true;
                            faceFeature = pstMetaUserData.Union1.stFaceAttr;
                            break;
                        default:
                            break;
                    }
                }
                if ((int)Target.FaceCapture == target)
                {
                    CaptureInfo info =
                        new CaptureInfo
                        {
                            _dataFacePanorama = dataFacePanorama,
                            _dataFacePic = dataFacePic,
                            _faceFeature = faceFeature,
                            _hasFaceFeature = hasFaceFeature
                        };
                    _concurrentQueue.Enqueue(info);
                }
                HuaWeiSdkHelper.IVS_User_FreeMetaData(out ptrstMetaTargetData);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
            finally
            {
                Marshal.FreeHGlobal(ptrstMetaTargetData);

                //HuaWeiSdkHelper.IVS_User_FreeMetaData(out ptrstMetaTargetData);
            }
        }

        #endregion
        #endregion

        private void ButtonDoing_OnClick(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(HuaWeiSdkHelper.GetLastErrorInfo());
        }

        private void MainWindow_OnClosed(object sender, EventArgs e)
        {
            _isExit = true;
            if (_timer.Enabled) _timer.Enabled = false;
            if (_ulRealHandleId > 0)
            {
                HuaWeiSdkHelper.IVS_PU_StopRealPlay(_ulIdentifyId, _ulRealHandleId);
            }
            if (_ulIdentifyId > 0)
            {
                HuaWeiSdkHelper.IVS_PU_Logout(_ulIdentifyId);
            }
            HuaWeiSdkHelper.IVS_PU_Cleanup();
            VideoFileStream.Close();
        }

        private void ButtonSave_OnClick(object sender, RoutedEventArgs e)
        {
            _isSave = true;
        }
    }
}
